Micron Document
Deavmi's coding shack

Node / mirrors / worcesterinit / files / monitor.go

Displaying Raw • Download

monitor.go cc973dfd54fff4f2d32eb71135e8d5bd3d1f246f (cc973dfd) Text, 6.28 KB

Tff7b72package Te6edf3main

Tff7b72import Tb4b4b4(
Ta5d6ff"context"
Ta5d6ff"fmt"
Ta5d6ff"io"
Ta5d6ff"os"
Ta5d6ff"os/exec"
Ta5d6ff"sync"

Ta5d6ff"new.git.deavmi.assigned.network/deavmi/glog.git/std/consts"
Te6edf3stdlogger Ta5d6ff"new.git.deavmi.assigned.network/deavmi/glog.git/std/logger"
Ta5d6ff"new.git.deavmi.assigned.network/deavmi/go-niknaks.git/slices"
Tb4b4b4)

Tff7b72func Tb4b4b4(Te6edf3b Te6edf3BruhTb4b4b4) Te6edf3NameTb4b4b4(Tb4b4b4) Tffa657string Tb4b4b4{
Tff7b72return Te6edf3bTb4b4b4.Te6edf3uTb4b4b4.Te6edf3NameTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tff7b72type Te6edf3Bruh Tff7b72struct Tb4b4b4{
T8b949e// original unit
Te6edf3u Te6edf3Unit

T8b949e// pointer to the loaded unit
Te6edf3lu Tff7b72*Te6edf3LoadedUnit

T8b949e// pointer to the manager instance
Te6edf3m Tff7b72*Te6edf3Manager

T8b949e// the command
Te6edf3cmd Tff7b72*Te6edf3execTb4b4b4.Te6edf3Cmd

T8b949e// pipes monitored
Te6edf3pipes Tb4b4b4[Tb4b4b4]Tff7b72*Te6edf3PipeMonitor
Te6edf3pipesLock Te6edf3syncTb4b4b4.Te6edf3Mutex
T8b949e// pipes []io.Closer

T8b949e// control signaling
Te6edf3ctx Te6edf3contextTb4b4b4.Te6edf3Context
Te6edf3cancelFunc Te6edf3contextTb4b4b4.Te6edf3CancelCauseFunc

T8b949e// logging
Te6edf3log Tff7b72*Te6edf3stdloggerTb4b4b4.Te6edf3StdLogger
Tb4b4b4}

Tff7b72func Te6edf3NewMonitorTb4b4b4(Te6edf3unit Te6edf3UnitTb4b4b4) Te6edf3Bruh Tb4b4b4{
Tff7b72return Te6edf3NewMonitorWithCtxTb4b4b4(Te6edf3unitTb4b4b4, Te6edf3contextTb4b4b4.Te6edf3BackgroundTb4b4b4(Tb4b4b4)Tb4b4b4)
Tb4b4b4}

T8b949e// creates a new monitor using the details
T8b949e// from the provided Unit and inherits the
T8b949e// given Context
Tff7b72func Te6edf3NewMonitorWithCtxTb4b4b4(Te6edf3unit Te6edf3UnitTb4b4b4, Te6edf3ctx Te6edf3contextTb4b4b4.Te6edf3ContextTb4b4b4) Te6edf3Bruh Tb4b4b4{
Tff7b72var Te6edf3b Te6edf3Bruh Tff7b72= Te6edf3BruhTb4b4b4{Te6edf3uTb4b4b4: Te6edf3unitTb4b4b4}

T8b949e// derive from the context one that we can get
T8b949e// a cancelation function
T8b949e//
T8b949e// this function let's us set a cause and then
T8b949e// cancel
Te6edf3bTb4b4b4.Te6edf3ctxTb4b4b4, Te6edf3bTb4b4b4.Te6edf3cancelFunc Tff7b72= Te6edf3contextTb4b4b4.Te6edf3WithCancelCauseTb4b4b4(Te6edf3ctxTb4b4b4)

T8b949e// Setup logging
T8b949e// TODO: Later inherit a logger passed in
Te6edf3bTb4b4b4.Te6edf3log Tff7b72= Te6edf3stdloggerTb4b4b4.Te6edf3NewStdLoggerTb4b4b4(Te6edf3fmtTb4b4b4.Te6edf3SprintfTb4b4b4(Ta5d6ff"Monitor %s"Tb4b4b4, Te6edf3unitTb4b4b4.Te6edf3NameTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4)
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3SetLevelTb4b4b4(Te6edf3constsTb4b4b4.Te6edf3LEVEL_TRACETb4b4b4)
Tb4b4b4}

Tff7b72func Tb4b4b4(Te6edf3b Tff7b72*Te6edf3BruhTb4b4b4) Te6edf3StartTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// configure a new command to execute and use
T8b949e// the context passed in
T8b949e//
T8b949e// this means when WE receive a cancel we can
T8b949e// get it but so will all derived contexts
Tff7b72var Te6edf3e Tff7b72*Te6edf3execTb4b4b4.Te6edf3Cmd Tff7b72= Te6edf3execTb4b4b4.Te6edf3CommandContextTb4b4b4(Te6edf3bTb4b4b4.Te6edf3ctxTb4b4b4, Te6edf3bTb4b4b4.Te6edf3uTb4b4b4.Te6edf3commandTb4b4b4, Te6edf3bTb4b4b4.Te6edf3uTb4b4b4.Te6edf3argsTb4b4b4...Tb4b4b4)

T8b949e// install environment variables
Tff7b72var Te6edf3envStrs Tb4b4b4[Tb4b4b4]Tffa657string Tff7b72= Te6edf3bTb4b4b4.Te6edf3makeEnvsTb4b4b4(Te6edf3bTb4b4b4.Te6edf3uTb4b4b4)
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3DebugTb4b4b4(Ta5d6ff"Installed %d environment variables for %s"Tb4b4b4, Tffa657lenTb4b4b4(Te6edf3envStrsTb4b4b4)Tb4b4b4, Te6edf3bTb4b4b4.Te6edf3uTb4b4b4.Te6edf3nameTb4b4b4)
Te6edf3eTb4b4b4.Te6edf3Env Tff7b72= Te6edf3envStrs

T8b949e// set working directory (if not specified then set to directory of `command`
T8b949e// if it is an absolute or we can find it from `command` or where service file
T8b949e// is located)
T8b949e// e.Dir

T8b949e// set the standard output and standard error writers
T8b949e// (that the process should write to)

T8b949e// after this c.Process becomes non-nil and we should
T8b949e// release resources (when process is done, via e.Wait()?)
Te6edf3eTb4b4b4.Te6edf3StartTb4b4b4(Tb4b4b4)
Tff7b72var Te6edf3proc Tff7b72*Te6edf3osTb4b4b4.Te6edf3Process Tff7b72= Te6edf3eTb4b4b4.Te6edf3Process
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3DebugTb4b4b4(Ta5d6ff"Process PID %d for '%s'..."Tb4b4b4, Te6edf3procTb4b4b4.Te6edf3PidTb4b4b4, Te6edf3bTb4b4b4.Te6edf3uTb4b4b4.Te6edf3NameTb4b4b4(Tb4b4b4)Tb4b4b4)

T8b949e// schedule a goroutine here with the monitor
T8b949e// function
Tff7b72go Te6edf3bTb4b4b4.Te6edf3monitorTb4b4b4(Tb4b4b4)

T8b949e// TODO: We also want to start some go routine that can
T8b949e// read from the standard out and collect logs for us
Te6edf3std_outTb4b4b4, Te6edf3err Tff7b72:= Te6edf3eTb4b4b4.Te6edf3StdoutPipeTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3err Tff7b72!= Tff7b72nil Tb4b4b4{
T8b949e// TODO: Handle this
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3ErrorTb4b4b4(Ta5d6ff"Could not obtain standard output pipe for '%s': %v"Tb4b4b4, Te6edf3bTb4b4b4.Te6edf3uTb4b4b4.Te6edf3NameTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3errTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
T8b949e// create a new pipe minitor and start it up
Te6edf3NewPipeMonitorTb4b4b4(Te6edf3bTb4b4b4, Te6edf3std_outTb4b4b4, Te6edf3bTb4b4b4.Te6edf3ctxTb4b4b4)Tb4b4b4.Te6edf3StartTb4b4b4(Tb4b4b4)
Tb4b4b4}

Te6edf3std_errTb4b4b4, Te6edf3err Tff7b72:= Te6edf3eTb4b4b4.Te6edf3StderrPipeTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3err Tff7b72!= Tff7b72nil Tb4b4b4{
T8b949e// TODO: Handle this
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3ErrorTb4b4b4(Ta5d6ff"Could not obtain standard error pipe for '%s': %v"Tb4b4b4, Te6edf3bTb4b4b4.Te6edf3uTb4b4b4.Te6edf3NameTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3errTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
T8b949e// create a new pipe minitor and start it up
Te6edf3NewPipeMonitorTb4b4b4(Te6edf3bTb4b4b4, Te6edf3std_errTb4b4b4, Te6edf3bTb4b4b4.Te6edf3ctxTb4b4b4)Tb4b4b4.Te6edf3StartTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72func Tb4b4b4(Te6edf3b Tff7b72*Te6edf3BruhTb4b4b4) Te6edf3AddPipeMonTb4b4b4(Te6edf3pipeMon Tff7b72*Te6edf3PipeMonitorTb4b4b4) Tb4b4b4{
Te6edf3bTb4b4b4.Te6edf3pipesLockTb4b4b4.Te6edf3LockTb4b4b4(Tb4b4b4)
Te6edf3bTb4b4b4.Te6edf3pipes Tff7b72= Tffa657appendTb4b4b4(Te6edf3bTb4b4b4.Te6edf3pipesTb4b4b4, Te6edf3pipeMonTb4b4b4)
Te6edf3bTb4b4b4.Te6edf3pipesLockTb4b4b4.Te6edf3UnlockTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tff7b72func Te6edf3NewPipeMonitorTb4b4b4(Te6edf3monitor Tff7b72*Te6edf3BruhTb4b4b4, Te6edf3r Te6edf3ioTb4b4b4.Te6edf3ReadCloserTb4b4b4, Te6edf3ctx Te6edf3contextTb4b4b4.Te6edf3ContextTb4b4b4) Te6edf3PipeMonitor Tb4b4b4{
Tff7b72return Te6edf3PipeMonitorTb4b4b4{Te6edf3mTb4b4b4: Te6edf3monitorTb4b4b4, Te6edf3pipeTb4b4b4: Te6edf3rTb4b4b4, Te6edf3ctxTb4b4b4: Te6edf3ctxTb4b4b4}
Tb4b4b4}

Tff7b72func Tb4b4b4(Te6edf3b Tff7b72*Te6edf3BruhTb4b4b4) Te6edf3monitorTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// wait for us to be cancelled
Tff7b72select Tb4b4b4{
Tff7b72case Tff7b72<-Te6edf3bTb4b4b4.Te6edf3ctxTb4b4b4.Te6edf3DoneTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3InfoTb4b4b4(Ta5d6ff"Got closing signal: %v"Tb4b4b4, Te6edf3contextTb4b4b4.Te6edf3CauseTb4b4b4(Te6edf3bTb4b4b4.Te6edf3ctxTb4b4b4)Tb4b4b4)
Tb4b4b4}

T8b949e// TODO: Perform shutdown
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3TraceTb4b4b4(Ta5d6ff"Shutting down pipes..."Tb4b4b4)
Tff7b72for Te6edf3p_idxTb4b4b4, Te6edf3p Tff7b72:= Tff7b72range Te6edf3bTb4b4b4.Te6edf3pipes Tb4b4b4{
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3TraceTb4b4b4(Ta5d6ff"(%d) Shutting down pipe '%v'..."Tb4b4b4, Te6edf3p_idxTb4b4b4, Te6edf3pTb4b4b4)
Te6edf3pTb4b4b4.Te6edf3StopTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72const Te6edf3BUFFER_SIZE Tff7b72= T79c0ff1000

T8b949e// combines the monitored pipe
T8b949e// with the destination of the
T8b949e// read data
Tff7b72type Te6edf3PipeMonitor Tff7b72struct Tb4b4b4{
T8b949e// the Monitor we are attached to
Te6edf3m Tff7b72*Te6edf3Bruh

T8b949e// pipe
Te6edf3pipe Te6edf3ioTb4b4b4.Te6edf3ReadCloser

T8b949e// context
Te6edf3ctx Te6edf3contextTb4b4b4.Te6edf3Context

T8b949e// logging
Te6edf3log Tff7b72*Te6edf3stdloggerTb4b4b4.Te6edf3StdLogger
Tb4b4b4}

Tff7b72func Tb4b4b4(Te6edf3pm Te6edf3PipeMonitorTb4b4b4) Te6edf3StringTb4b4b4(Tb4b4b4) Tffa657string Tb4b4b4{
Tff7b72return Te6edf3fmtTb4b4b4.Te6edf3SprintfTb4b4b4(Ta5d6ff"%T (unit: %s, pipe: %v)"Tb4b4b4, Te6edf3pmTb4b4b4, Te6edf3pmTb4b4b4.Te6edf3mTb4b4b4.Te6edf3NameTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3pmTb4b4b4.Te6edf3pipeTb4b4b4)
Tb4b4b4}

T8b949e// Spawns a go routine to start this PipeMonitor
T8b949e//
T8b949e// This will eventually cause it to be added to
T8b949e// the Monitor's pipe list
Tff7b72func Tb4b4b4(Te6edf3pm Te6edf3PipeMonitorTb4b4b4) Te6edf3StartTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72go Te6edf3pmTb4b4b4.Te6edf3logMonitorTb4b4b4(Tb4b4b4)
Tb4b4b4}

T8b949e// Stops the pipe monmitor
T8b949e//
T8b949e// This is accomplished by:
T8b949e//
T8b949e// 1. Updating the context (TODO: not needed but it is nice)
T8b949e// 2. Close()'ing the ReadCloser calling the PipeMonitor's
T8b949e// `Read()` to unblock and the Goroutine to end
Tff7b72func Tb4b4b4(Te6edf3pm Te6edf3PipeMonitorTb4b4b4) Te6edf3StopTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3pmTb4b4b4.Te6edf3logTb4b4b4.Te6edf3DebugTb4b4b4(Ta5d6ff"Stopping %v..."Tb4b4b4, Te6edf3pmTb4b4b4)
Tff7b72if Te6edf3e Tff7b72:= Te6edf3pmTb4b4b4.Te6edf3pipeTb4b4b4.Te6edf3CloseTb4b4b4(Tb4b4b4)Tb4b4b4; Te6edf3e Tff7b72!= Tff7b72nil Tb4b4b4{
Te6edf3pmTb4b4b4.Te6edf3logTb4b4b4.Te6edf3ErrorTb4b4b4(Ta5d6ff"Error when closing internal pipe during shutdown: %v"Tb4b4b4, Te6edf3eTb4b4b4)
Tb4b4b4}
Te6edf3pmTb4b4b4.Te6edf3logTb4b4b4.Te6edf3DebugTb4b4b4(Ta5d6ff"%v stopped"Tb4b4b4, Te6edf3pmTb4b4b4)
Tb4b4b4}

T8b949e// log monitor for the given reader
T8b949e//
T8b949e// waits for bytes and when it gets
T8b949e// an error then it exits.
Tff7b72func Tb4b4b4(Te6edf3b Tff7b72*Te6edf3PipeMonitorTb4b4b4) Te6edf3logMonitorTb4b4b4(Tb4b4b4) Tb4b4b4{
T8b949e// Add `r` to b.pipes
Te6edf3bTb4b4b4.Te6edf3mTb4b4b4.Te6edf3AddPipeMonTb4b4b4(Te6edf3bTb4b4b4)

Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3TraceTb4b4b4(Ta5d6ff"Log monitor for '%s' on fd '%v' enter"Tb4b4b4, Te6edf3bTb4b4b4.Te6edf3mTb4b4b4.Te6edf3NameTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3bTb4b4b4.Te6edf3pipeTb4b4b4)
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3TraceTb4b4b4(Ta5d6ff"Log monitor for '%s' on fd '%v' using buffer size %d"Tb4b4b4, Te6edf3BUFFER_SIZETb4b4b4)

Tff7b72var Te6edf3buff Tb4b4b4[Tb4b4b4]Tffa657byte Tff7b72= Tffa657makeTb4b4b4(Tb4b4b4[Tb4b4b4]Tffa657byteTb4b4b4, Te6edf3BUFFER_SIZETb4b4b4)
Tff7b72for Tb4b4b4{
T8b949e// we read at most `BUFFER_SIZE` bytes per call
Te6edf3nTb4b4b4, Te6edf3e Tff7b72:= Te6edf3bTb4b4b4.Te6edf3pipeTb4b4b4.Te6edf3ReadTb4b4b4(Te6edf3buffTb4b4b4)
Tff7b72if Te6edf3e Tff7b72!= Tff7b72nil Tb4b4b4{
T8b949e// TODO: Check context in case maybe something basd happened
T8b949e// like process closed one end of pipe _instead_ of us initiating
T8b949e// a tare down
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3DebugTb4b4b4(Ta5d6ff"Log monitor error returned whilst reading: %v"Tb4b4b4, Te6edf3eTb4b4b4)
Tff7b72break
Tb4b4b4}
Te6edf3buff Tff7b72= Te6edf3buffTb4b4b4[T79c0ff0Tb4b4b4:Te6edf3nTb4b4b4] T8b949e// trim to bytes got

T8b949e// TODO: Do something with bytes
Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3TraceTb4b4b4(Ta5d6ff"Got %d bytes: '%s'"Tb4b4b4, Te6edf3nTb4b4b4, Tb4b4b4(Tffa657stringTb4b4b4)Tb4b4b4(Te6edf3buffTb4b4b4)Tb4b4b4)
Tb4b4b4}

Te6edf3bTb4b4b4.Te6edf3logTb4b4b4.Te6edf3TraceTb4b4b4(Ta5d6ff"Log monitor for '%s' on fd '%v' exit"Tb4b4b4, Te6edf3bTb4b4b4.Te6edf3uTb4b4b4.Te6edf3NameTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3rTb4b4b4)

T8b949e// Remove `r` from b.pipes
Te6edf3bTb4b4b4.Te6edf3pipesLockTb4b4b4.Te6edf3LockTb4b4b4(Tb4b4b4)
Te6edf3bTb4b4b4.Te6edf3pipes Tff7b72= Te6edf3slicesTb4b4b4.Te6edf3RemoveElemTb4b4b4(Te6edf3rTb4b4b4, Te6edf3bTb4b4b4.Te6edf3pipesTb4b4b4)
Te6edf3bTb4b4b4.Te6edf3pipesLockTb4b4b4.Te6edf3UnlockTb4b4b4(Tb4b4b4)
Tb4b4b4}

T8b949e// signal
T8b949e// Stop the process
T8b949e//
T8b949e// 1. calls `Kill()`
T8b949e// 2. cancels the `b.ctx`
T8b949e// 2.1 this unblocks Goroutine running `monitor()`
T8b949e// 2.2 this causes the process in `b.cmd.process` to kill the process
Tff7b72func Tb4b4b4(Te6edf3b Tff7b72*Te6edf3BruhTb4b4b4) Te6edf3StopTb4b4b4(Tb4b4b4) Tb4b4b4{

Tb4b4b4}

Tff7b72func Tb4b4b4(Te6edf3m Tff7b72*Te6edf3BruhTb4b4b4) Te6edf3makeEnvsTb4b4b4(Te6edf3u Te6edf3UnitTb4b4b4) Tb4b4b4[Tb4b4b4]Tffa657string Tb4b4b4{
Tff7b72var Te6edf3vars Tb4b4b4[Tb4b4b4]Tffa657string
Tff7b72for Te6edf3kTb4b4b4, Te6edf3v Tff7b72:= Tff7b72range Te6edf3uTb4b4b4.Te6edf3GetEnvsTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3varStr Tff7b72:= Te6edf3makeEnvStringTb4b4b4(Te6edf3kTb4b4b4, Te6edf3vTb4b4b4)
Te6edf3vars Tff7b72= Tffa657appendTb4b4b4(Te6edf3varsTb4b4b4, Te6edf3varStrTb4b4b4)
Te6edf3mTb4b4b4.Te6edf3logTb4b4b4.Te6edf3TraceTb4b4b4(Ta5d6ff"Will install environment variable %s into %s"Tb4b4b4, Te6edf3uTb4b4b4.Te6edf3nameTb4b4b4, Te6edf3varStrTb4b4b4)
Tb4b4b4}
Tff7b72return Te6edf3vars
Tb4b4b4}

Tff7b72func Te6edf3makeEnvStringTb4b4b4(Te6edf3name Tffa657stringTb4b4b4, Te6edf3value Tffa657stringTb4b4b4) Tffa657string Tb4b4b4{
Tff7b72return Te6edf3fmtTb4b4b4.Te6edf3SprintfTb4b4b4(Ta5d6ff"%s=%s"Tb4b4b4, Te6edf3nameTb4b4b4, Te6edf3valueTb4b4b4)
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.08s